import { ref, reactive, onUnmounted, onMounted, nextTick } from 'vue'
import {
	Leafer,
	App,
	Text,
	Image,
	ImageEvent,
	ZoomEvent,
	ResizeEvent,
	ChildEvent,
	LeaferEvent,
	PropertyEvent,
	Group,
	ImageManager,
	Frame,
	Box
} from 'leafer-ui'
import { PenTool } from '../tools/PenTool'
import { TextTool } from '../tools/TextTool'

import type { ITool, IToolConfig, IToolReturn, IToolType } from '../types'
import { createBaseTool } from '../core/BaseTool'
import '@leafer-in/editor'
import '@leafer-in/view'
import '@leafer-in/animate'
import '@leafer-in/viewport'

import { ShapeTool } from '../tools/ShapeTool'
import { EaserTool } from '../tools/EaserTool'
import { isFunction } from '@/utils/is'
import { useDebounceFn, useEventListener } from '@vueuse/core'
import useHistoryUtil from './useHistoryUtil'
import { getCursor } from '../config'
import { useHotKeyUtil } from './useHotKeyUtil'

const zoomConfig = {
	step: 0.1,
	min: 0.1,
	max: 5,
	padding: 0
}
export const useWhiteBoard = (containerId: string) => {
	// 初始化Leafer
	let app: App
	// 响应式配置
	const config = reactive<IToolConfig>({
		pen: { color: '#FF4C26', strokeWidth: 8, opcity: 1 },
		eraser: { size: 20 },
		text: { fontSize: 20, color: '#FF4C26', limitBox: false },
		shape: {
			color: '#FF4C26',
			strokeWidth: 8,
			type: 'rect'
		}
	})
	const activeTool = ref('')
	const loading = ref(false)
	let fitScale = 1
	const scale = ref(1)
	const dragable = ref(false)
	const target = () => app.tree
	const historyUtil = useHistoryUtil((v: any) => {
		target().set(v)
	})

	// 工具Map
	let toolMap: Record<IToolType, any> = {
		pen: PenTool,
		text: TextTool,
		shape: ShapeTool,
		eraser: EaserTool
	}
	let toolManager: any
	const commitHistory = () => {
		historyUtil.commit(target().toJSON())
	}
	// 切换工具
	const setActiveTool = (toolName: IToolType | '') => {
		target().set({
			cursor: getCursor(toolName, config)
		})
		// if (activeTool.value === toolName) return
		toolManager?.unregisterEvents?.()
		activeTool.value = toolName
		if (toolName === '') {
			app.hittable = false
			return
		} else {
			app.hittable = true
		}
		const tool = toolMap[toolName]
		if (!tool) return
		toolManager = createBaseTool(
			app,
			tool({ app, config, commit: commitHistory, target })
		)
		toolManager.registerEvents()
	}
	const init = () => {
		app = new App({
			view: containerId,
			editor: {
				//是否启用框选功能
				boxSelect: false,
				editBox: false,
			},
			smooth: true,
			// pointer: { touch: true },
			// touch: { preventDefault: true },
			move: {
				holdRightKey: true
			},
			wheel: {
				moveSpeed: 0,
        // preventDefault: true
			},
			usePartRender: false
		})
		app.on(ZoomEvent.ZOOM, function () {
			scale.value = +(app.tree.scale ?? 1) / fitScale
		})
	}
	const initData = (dataStr: string | undefined | null) => {
		if (target().children.length) {
			target().clear()
			initRotate()
		}
		if (!!dataStr) {
			const data = JSON.parse(dataStr)
			historyUtil.init(data)
		} else {
			historyUtil.init(target().toJSON())
		}
		setActiveTool('')
	}
	const initRotate = () => {
		if (!app?.tree) return
		if (app.tree.rotation === 0) return
		app.tree.rotateOf('center', -(app.tree.rotation || 0))
	}
	const initImg = async (data: {
		url: string
		penData: string | undefined | null
	}) => {
		loading.value = true
		return new Promise<void>((resolve, reject) => {
			scale.value = 1
			fitScale = 1
			app.data.fitScale = fitScale
			app.config.zoom = {
				min: zoomConfig.min * fitScale,
				max: zoomConfig.max * fitScale
			}
			initData(data.penData)
			loading.value = false
			resolve()
		})
	}
	const hanRotate = (isLeft: boolean) => {
		app.tree.rotateOf('center', isLeft ? -90 : 90)
	}
	const hanScale = (isAdd: boolean) => {
		const step = zoomConfig.step
		let newScale = scale.value + (isAdd ? step : -step)
		if (newScale < zoomConfig.min) newScale = zoomConfig.min
		if (newScale > zoomConfig.max) newScale = zoomConfig.max
		scale.value = newScale
		const target = newScale * fitScale
		app.zoom(target, zoomConfig.padding, false, 0.2)
	}
	const clear = () => {
		target().clear()
		commitHistory()
	}
	onMounted(() => {
		init()
	})
	// 清理资源
	onUnmounted(() => {
		app.destroy()
	})
	useEventListener('unload', () => {
		const { list } = Leafer
		list.forEach((leafer) => (leafer as Leafer).destroy(true))
		list.destroy()
		ImageManager.destroy()
	})
	const destroy = () => {
		app.destroy()
	}
	const setDragable = (v: boolean) => {
		dragable.value = v
		app.config.move = {
			...(app.config.move || {}),
			drag: v
		}
	}
	watch(
		() => config.pen.opcity,
		() => {
			setActiveTool('pen')
		}
	)
  useHotKeyUtil({
		activeTool,
		setActiveTool,
		historyUtil,
		hanScale,
		toolConfig: config
	})
	return {
		activeTool,
		config,
		setActiveTool,
		initImg,
		historyUtil,
		hanRotate,
		hanScale,
		clear,
		loading,
		scale,
		destroy,
		setDragable,
		dragable
	}
}
